package com.wanban.downloader.manager

import android.app.Application
import android.text.TextUtils
import android.util.Log
import android.widget.Toast
import com.arialyy.aria.core.Aria
import com.blankj.utilcode.util.FileUtils
import com.blankj.utilcode.util.NetworkUtils
import com.blankj.utilcode.util.SPUtils
import com.wanban.downloader.db.DownloadEntity
import com.wanban.downloader.listener.OnDownloadListener
import com.wanban.downloader.model.Status
import com.wanban.downloader.utils.CommonUtils
import com.wanban.downloader.utils.Constants
import com.wanban.downloader.utils.ContextProvider
import com.wanban.downloader.utils.DatabaseUtils
import com.wanban.downloader.utils.FileDownloadUtils
import com.wanban.downloader.utils.MyThreadUtils


abstract class BaseDownloadManager {

    companion object {
        const val TAG = "MultiDownload"
        const val MAX_DOWNLOAD_COUNT = 2
        const val DOWNLOAD_TYPE_SELF = 0
        const val DOWNLOAD_TYPE_EXO = 1
    }

    private val downloadQueue by lazy { ArrayList<DownloadEntity>() }

    private var downloadListener: OnDownloadListener? = null

    abstract fun getDownloadType(): Int

    fun setDownloadListener(listener: OnDownloadListener?) {
        downloadListener = listener
    }

    /** 执行下载 */
    abstract fun executeStart(task: DownloadEntity)

    /**
     * 初始化，恢复下载队列内容，但是不开始下载
     */
    open fun init(application: Application) {
        Aria.init(application)
        if (downloadQueue.isNotEmpty()) return
        DatabaseUtils.getDownloadTask {
            if (it.isEmpty()) return@getDownloadTask
            downloadQueue.clear()
            downloadQueue.addAll(it)
        }
    }

    /**
     * 尝试启动可以下载的内容
     */
    open fun resumeAllDownload() {
        val runningCount = getRunningTaskCount()
        if (runningCount >= MAX_DOWNLOAD_COUNT) {
            Log.e(TAG, "下载队列达到极限，无法进行新的下载")
            return
        }
        // 找到可以尝试回复的下载
        val canStartList = downloadQueue.filter {
            it.state == Status.PENDING || it.state == Status.START
                    || it.state == Status.PREPARE || it.state == Status.DOWNLOADING
        }
        if (canStartList.isEmpty()) return
        val size = canStartList.size
        for (index in 0 until MAX_DOWNLOAD_COUNT.coerceAtMost(size)) {
            val task = canStartList[index]
            task.state = Status.PENDING
            updateTaskAndSendMessage(task)
            executeStart(task)
        }
    }


    /**
     * 新增下载
     */
    @Synchronized
    open fun startDownload(task: DownloadEntity) {
        val queueCount = downloadQueue.count { it.state != Status.SUCCESS && it.state != Status.IDLE }
        if (queueCount >= 20) {
            Toast.makeText(ContextProvider.application, "达到下载最大数，无法新增新的下载！！", Toast.LENGTH_SHORT).show()
            return
        }

        if (TextUtils.isEmpty(task.url) || TextUtils.isEmpty(task.videoName)) {
            Log.e(TAG, "url or videoName is null")
            return
        }
        if (NetworkUtils.isMobileData() && isOnlyWifiDownload()) { // 不允许使用流量下载
            Log.e(TAG, "${task.getFileName()} => 当前不允许使用流量下载...")
            onErrorStatus(task.url, "不允许流量下载！")
            return
        }
        // 查询是否能添加下载
        val addTask = getTaskByUrl(task.url)
        if (addTask == null) { // 当前下载没有在队列中
            // 先处于准备阶段，到开始下载之间的过程都是准备阶段
            onPendingStatus(task)
            // 加入下载队列
            downloadQueue.add(task)
            Log.e(TAG, "${task.getFileName()} => 加入下载队列...")
            // 当前正在下载的任务数量
            val runningTaskCount = getRunningTaskCount()
            if (runningTaskCount >= MAX_DOWNLOAD_COUNT) {
                Log.e(TAG, "已达到最大队列，无法进行下载，等待其他下载完成...")
                return
            }
            // 可以准备下载
            onPrepareStatus(task)
            // 先解析对应的url
            executeStart(task)
            return
        }

        // 此处表示当前任务已经在队列中
        Log.e(TAG, "${task.getFileName()} => 当前下载已经加入下载...")
        if (addTask.state == Status.SUCCESS) {
            Toast.makeText(ContextProvider.application, "视频已完成下载！", Toast.LENGTH_SHORT).show()
            return
        }

        val runningList = downloadQueue.filter { it.state == Status.DOWNLOADING || it.state == Status.PREPARE || it.state == Status.START }
        if (runningList.size < MAX_DOWNLOAD_COUNT) { // 可以直接启动
            // 可以准备下载
            onPrepareStatus(addTask)
            // 下载视频
            executeStart(addTask)
            return
        }

        // 此处表示当前下载数达到最大值
        // 找到启动最久的任务并暂停
        val lastTask = runningList.sortedByDescending { it.startTaskTime }.lastOrNull()
        if (lastTask != null) {
            onStopStatus(lastTask.url, false)
            onPendingStatus(lastTask)
        }
        // 启动当前的任务
        onPrepareStatus(addTask)
        // 下载视频
        executeStart(addTask)
    }


    /**
     * 暂停下载
     */
    @Synchronized
    open fun stopDownload(url: String) {
        stopDownloadTask(url)
        onStopStatus(url)
    }

    internal open fun stopDownloadTask(url: String) {

    }


    /**
     * 继续下载
     */
    @Synchronized
    open fun resumeDownload(url: String) {
        val task = getTaskByUrl(url) ?: return
        startDownload(task)
    }

    /**
     * 删除下载
     */
    @Synchronized
    open fun deleteDownload(url: String) {
        val task = getTaskByUrl(url) ?: return
        // 删除目录
        MyThreadUtils.executeSingleTask {
            FileUtils.deleteAllInDir(FileDownloadUtils.getOrCreateVideoRootFileDirPath(task.getFileName()))
            DatabaseUtils.deleteTask(url)
            task.state = Status.DELETE
            Log.e(TAG, "${task.videoName} => 视频已删除")
            sendMessage(task)
            return@executeSingleTask downloadQueue.remove(task)
        }
    }

    protected open fun onPendingStatus(task: DownloadEntity) {
        task.state = Status.PENDING
        updateTaskAndSendMessage(task)
    }

    protected open fun onPrepareStatus(task: DownloadEntity) {
        task.state = Status.PREPARE
        updateTaskAndSendMessage(task)
    }

    protected open fun onStartStatus(url: String) {
        val task = getTaskByUrl(url) ?: return
        task.state = Status.START
        Log.e(TAG, "${task.getFileName()} => onStart...")
        updateTaskAndSendMessage(task)
    }

    protected open fun onProgressStatus(url: String, speed: Long, percent: Float, currentLength: Long) {
        val task = getTaskByUrl(url) ?: return
        // 屏蔽无效的状态
        if (task.state != Status.DOWNLOADING && task.state != Status.PREPARE && task.state != Status.START) return
        Log.e(
            TAG, "${task.getFileName()} => onProgress...${CommonUtils.getFormatSpeedString(speed)} ${CommonUtils.getFormatPercentString(percent)}"
        )
        task.state = Status.DOWNLOADING
        task.speed = speed
        task.percent = percent
        task.contentLength = currentLength
        updateTaskAndSendMessage(task)
    }

    protected open fun onStopStatus(url: String, isAutoStartNext: Boolean = true) {
        val task = getTaskByUrl(url) ?: return
        Log.e(TAG, "${task.getFileName()} => onPause...")
        if (task.state == Status.SUCCESS) return
        task.state = Status.STOP
        updateTaskAndSendMessage(task)
        if (isAutoStartNext) {
            readyToNextTask()
        }
    }

    protected open fun onErrorStatus(url: String, errorMsg: String?) {
        val task = getTaskByUrl(url) ?: return
        Log.e(TAG, "${task.getFileName()} => onError...$errorMsg")
        if (task.state == Status.SUCCESS) return
        task.state = Status.ERROR
        updateTaskAndSendMessage(task)
        readyToNextTask()
    }

    protected open fun onSuccessStatus(url: String) {
        Log.e(TAG, "onSuccessStatus...")
        val task = getTaskByUrl(url) ?: return
        task.state = Status.SUCCESS
        Log.e(TAG, "${task.getFileName()} => onSuccessStatus...视频下载完成")
        updateTaskAndSendMessage(task)
        readyToNextTask()
    }

    private fun readyToNextTask() {
        // 先寻找是否还有在等待的任务
        val runningCount = getRunningTaskCount()
        if (runningCount >= MAX_DOWNLOAD_COUNT) return
        val pendingList = downloadQueue.filter { it.state == Status.PENDING }
        if (pendingList.isEmpty()) {
            val errorList = downloadQueue.filter { it.state == Status.ERROR && it.retryTime < Constants.MAX_RETRY_TIME }
            if (errorList.isEmpty()) return
            for (index in 0 until (MAX_DOWNLOAD_COUNT - runningCount).coerceAtMost(errorList.size)) {
                val task = errorList[index]
                task.retryTime += 1
                // 先解析对应的url
                executeStart(task)
            }
            return
        }
        for (index in 0 until (MAX_DOWNLOAD_COUNT - runningCount).coerceAtMost(pendingList.size)) {
            val task = pendingList[index]
            // 先解析对应的url
            executeStart(task)
        }
    }


    /**
     * 是否存在未完成的任务
     */
    fun hasDownloadingTask(success: (hasDownloading: Boolean) -> Unit) {
        DatabaseUtils.hasDownloadingTask(success)
    }

    fun updateTaskAndSendMessage(task: DownloadEntity) {
        updateTask(task)
        sendMessage(task)
    }

    private fun updateTask(task: DownloadEntity) {
        // 跟新db
        DatabaseUtils.insertOrUpdateTask(task)
    }


    private fun sendMessage(task: DownloadEntity) {
//        EventBus.getDefault().post(task)
        downloadListener?.onDownloadStatusChanged(task)
//        when (task.state) {
//            Status.PENDING -> downloadListener?.onPending(task)
//            Status.PREPARE -> downloadListener?.onPrepare(task)
//            Status.START -> downloadListener?.onStart(task)
//            Status.DOWNLOADING -> downloadListener?.onDownloading(task)
//            Status.STOP -> downloadListener?.onStop(task)
//            Status.ERROR -> downloadListener?.onError(task)
//            Status.MERGE -> downloadListener?.onMerge(task)
//            Status.SUCCESS -> downloadListener?.onSuccess(task)
//            else -> {}
//        }
    }

    fun getSuccessTasks(complete: (tasks: ArrayList<DownloadEntity>) -> Unit) {
        DatabaseUtils.getSuccessDownloadTasks(complete)
    }

    fun getAlbumDownloads(video: Long, complete: (tasks: ArrayList<DownloadEntity>) -> Unit) {
        DatabaseUtils.getAlbumDownloads(video, complete)
    }

    fun setOnlyWifiDownload(isOnlyWifi: Boolean) {
        SPUtils.getInstance().put(Constants.SP_KEY_IS_ONLY_WIFI_DOWNLOAD, isOnlyWifi)
    }

    fun isOnlyWifiDownload(): Boolean {
        return SPUtils.getInstance().getBoolean(Constants.SP_KEY_IS_ONLY_WIFI_DOWNLOAD, true)
    }

    fun getDownloadTask(video: Long, episode: Int, sourceId: Int, complete: (task: DownloadEntity?) -> Unit) {
        DatabaseUtils.getDownloadTask(video, episode, sourceId, complete)
    }

    fun getTaskByUrl(url: String): DownloadEntity? {
        return downloadQueue.firstOrNull { it.url == url }
    }

    fun getUnSuccessDownload(): ArrayList<DownloadEntity> {
        return downloadQueue.filter { it.state != Status.SUCCESS } as ArrayList<DownloadEntity>
    }

    private fun getRunningTaskCount(): Int {
        return downloadQueue.count { it.state == Status.DOWNLOADING || it.state == Status.PREPARE || it.state == Status.START }
    }

    /**
     * 缓存封面图
     */
    protected fun cacheCoverImage(url: String, videoName: String, coverUrl: String?) {
        if (TextUtils.isEmpty(coverUrl)) return
        val path = FileDownloadUtils.getOrCreateCoverFilePath(videoName)
        if (FileUtils.isFileExists(path) && FileUtils.isFile(path) && FileUtils.getLength(path) > 0) {
            return
        }
        FileDownloadUtils.downloadFile(coverUrl, path) { isSuccess, _ ->
            if (isSuccess) {
                val task = getTaskByUrl(url) ?: return@downloadFile
                task.coverFilePath = path
                DatabaseUtils.insertOrUpdateTask(task)
            } else {
                FileUtils.delete(path)
            }
        }
    }
}